package rpc

import(
	"fmt"
	"math/big"
	"errors"
	"strings"
)

type RPCParam struct {
	jsonrpc string
	Method 	string
	Params 	interface{}
	Id		int
}
type RPCResult struct {
	Jsonrpc string
	Id		int
	Result  interface{}
	Error RPCResultError
}
type RPCResultError struct {
	Code int
	Message string
}
//RPCParam
func (m *RPCParam) SetJsonrpc ()(){
	m.jsonrpc = "2.0"
}
func (m *RPCParam) SetMethod (method string)(){
	m.Method =  method
}
func (m *RPCParam) SetParams (params interface{})(){
	m.Params = params
}
func (m *RPCParam) SetId (id int)(){
	m.Id =  id
}
//RPCResult
func (m *RPCResult) SetId (id int)(){
	m.Id =  id
}
func (m *RPCResult) SetResult(result string)(){
	m.Result = result
}

func QueryBalance(Account string, state string)(int64, error){
	var rpc RPCParam
	rpc.SetJsonrpc()
	rpc.SetId(2)
	rpc.SetMethod("eth_getBalance")
	params := new([]interface{})
	*params = append(*params, Account)
	*params = append(*params, state)
	rpc.SetParams(*params)
	value,error := HttpEthPost(rpc,SetEthHost())
	if error != nil {
		return 0, error
	}
	var s string
	switch v := value.(type) {
	case string :
		s = v
	default:
		return 0, errors.New("query error")
	}
	val, error := StringToBigInt(s, 0)
	if error!=nil {
		fmt.Println(error)
		return 0, error
	}
	val = val.Div(val, big.NewInt(1000000))
	val = val.Div(val, big.NewInt(1000000))
	val = val.Div(val, big.NewInt(1000000))
	return val.Int64(), nil
}

func StringToBigInt(num string, base int) (*big.Int, error) {
	error := errors.New("wrong format")
	if len(num) == 0 {
		return nil, error
	}
	if num == "0" {
		return big.NewInt(0), nil
	}
	num = strings.ToLower(num)
	if base == 0 {
		//自动匹配
		if strings.HasPrefix(num, "0x") {
			num = num[2:]
			base = 16
		} else if strings.HasPrefix(num, "0") {
			num = num[1:]
			base = 8
		} else if strings.HasSuffix(num, "b") {
			num = num[:len(num)-1]
			base = 2
		}
	}
	res := big.NewInt(0)
	mul := big.NewInt(int64(base))
	for i:=0;i<len(num);i++{
		res = res.Mul(res, mul)
		v := int64(num[i]-48)
		if v > 9 {
			v = v - 39
		}
		res = res.Add(res, big.NewInt(v))
	}
	return res, nil
}

func ImportRawKey(keydata string, password string)(string, error){
	var rpc RPCParam
	rpc.SetJsonrpc()
	rpc.SetId(2)
	rpc.SetMethod("personal_importRawKey")
	params := new([]interface{})
	*params = append(*params, keydata)
	*params = append(*params,password)
	rpc.SetParams(*params)
	keyaddress, error := HttpEthPost(rpc,SetEthHost())
	if error!=nil {
		return "", error
	}
	var s string
	switch v := keyaddress.(type) {
	case string :
		s = v
	default:
		return "",errors.New("send transaction error")
	}
	return s, nil
}

func SendTransaction(From string, To string, value string, passphrase string)(string, error){
	var rpc RPCParam
	rpc.SetJsonrpc()
	rpc.SetId(2)
	rpc.SetMethod("personal_sendTransaction")
	params := new([]interface{})
	transaction := new(Transaction)
	transaction.From = From
	transaction.To = To
	transaction.Value = ``
	*params = append(*params, *transaction)
	*params = append(*params, passphrase)
	rpc.SetParams(*params)
	txid,error := HttpEthPost(rpc,SetEthHost())
	if error != nil {
		return "", error
	}
	var s string
	switch v := txid.(type) {
	case string :
		s = v
	default:
		return "",errors.New("send transaction error")
	}
	return s,nil
}

func QueryTransaction(txid string)(*TransactionResult, error){
	var rpc RPCParam
	rpc.SetJsonrpc()
	rpc.SetId(2)
	rpc.SetMethod("eth_getTransactionByHash")
	params := new([]interface{})
	*params = append(*params, txid)
	rpc.SetParams(*params)
	value, error := HttpEthPost(rpc,SetEthHost())
	if error != nil {
		return nil, error
	}
	m := value.(map[string]interface{})
	result := TransactionResult{
		m["hash"].(string),
		m["nonce"].(string),
		m["blockHash"].(string),
		"",
		m["transactionIndex"].(string),
		m["from"].(string),
		m["to"].(string),
		m["value"].(string),
		m["gas"].(string),
		m["gasPrice"].(string),
		"",
	}
	return &result, nil
}

type Transaction struct {
	From string  `json:"from"`
	To string    `json:"to"`
	Value string `json:"value, omitempty"`
	//Data string  `json:"data, omitempty"`
	//Gas  string  `json:"gas, omitempty"`
	//GasPrice string `json:"gasPrice"`
}

type TransactionResult struct {
	Hash string   `json:"hash"`
	Nonce string  `json:"nonce"`
	BlockHash string `json:"blockHash"`
	BlockNumber string `json:"blockNumber"`
	TransactionIndex string `json:"transactionIndex"`
	From string `json:"from"`
	To string `json:"to"`
	Value string `json:"value"`
	Gas string `json:"gas"`
	GasPrice string `json:"gasPrice"`
	Input string `json:"input"`
}

